/*
 * detect_cl.h
 *
 *  Created on: 2016年6月12日
 *      Author: guyadong
 */

#ifndef FACEDETECT_DETECT_CL_H_
#define FACEDETECT_DETECT_CL_H_
#include "detect_cl_types.h"
#ifndef GF_DLL_DECL
#ifdef _WIN32
#ifdef GF_DLL_BUILD
#define GF_DLL_DECL  __declspec(dllexport)
#define GF_DLL_EXTERN
#else
#define GF_DLL_DECL  __declspec(dllimport)
#define GF_DLL_EXTERN
#endif
#else
#define GF_DLL_DECL
#define GF_DLL_EXTERN
#endif
#endif
/*
 * detect_cl动态库接口定义
 * 所有接口函数出错的时候会抛出异常
 * */
namespace gdface{
/*  全局常量定义 */
const static size_t	DETECT_WIN_SIZE = 24; // 最小检测窗口
const static size_t	MIN_DIST_SIZE = 4; // 最小检测窗口的目标分布范围尺寸
const static size_t	MIN_SUM_THRESHOLD =13; // 最小检测窗口的目标分布范围尺寸
const static float	DETECT_WIN_SCALE_RATIO = 1.25f;	// 基于检测窗口DETECT_WIN_SIZE的放大倍率
const static float	DETECT_WIN_SCALE_COMP = 0.5f;   	// 基于检测窗口DETECT_WIN_SIZE的放大 补偿系数
const static size_t	DEFAULT_MIN_DETECT_WIN_SIZE = 40; // 默认的最小检测窗口
const static float	DEFAULT_MAX_DETECT_WIN_RATIO = 0.7f;// 默认的最大检测窗口与图像尺寸的比例
const static size_t	SCALE_SIZE = 10; // 检测窗口放大级数
const static size_t DEFAULT_DETECT_WIN_SHRINK_FLOOR = 100; // 默认的最小检测窗口缩小下限

/*
 * 图像检测参数包类
 * adaboost目标检测算法的最小检测窗口是24x24,所有的haar特征都是基于这个最小窗口训练的，
 * 在对一幅图像图检测时，为了能检测到不同大小的目标，需要在24x24最小检测窗口的基础上不断放大检测窗口对整个图像进行扫描，
 * 以实现对不同大小目标的检测。
 * =====检测窗口定义=====
 * 图像检测窗口大小的定义方式有两种类型：普通的以像素为单位的整数类型和归一化的浮点类型，
 * 像素为单位的整数类型很容易理解不再赘述。
 * 归一化的浮点类型定义，是指用检测窗口大小(像素)与图像尺寸的比例来定义检测窗口的尺寸 
 * (所以用这里的窗口大小必须是一个大于0小于1的浮点数)，
 * =====关于"图像尺寸"的特别说明=====
 * 这里所指的图像大小是指图像宽高中的最小值
 * 比如 如果一个检测窗口的归一化尺寸是0.7,那么对于宽高是1000x600的图像,换算成像素尺寸则是600x0.7=420(像素)，
 * =====检测范围=====
 * 最小检测窗口到最大检测窗口之间所有的检测窗口称为检测范围，在这个尺寸范围内的目标才有可能被检测到
 * 对于检测范围有两种类型的成员变量进行描述：detect_range_f和detect_range_i,
 * 在定义检测范围时可以使用两种定义的任何一种，但不能同时使用两种，如果两个变量都设置了，优先使用detect_range_f。
 * detect_range_i是我们常见的整数类型,即以像素为单位指定检测窗口大小,第一个成员s0指定最大检测窗口，第二个成员s1指定最小检测窗口
 * detect_range_f是前面说的归一化的浮点类型,也是两个成员变量,含义同上
 * =====检测范围调整=====
 * 目标检测的时候对于每个尺寸的检测窗口，都要对整幅图像进行扫描,
 * 如果使用默认生成的图像检测参数对象来进行目标检测,则图像检测范围是{0.7f,0.0f}(s1为0时为最小检测窗口),即从图像尺寸0.7倍的窗口到
 * 最小检测窗口之间的所有检测窗口都要被扫描，基本上是全范围扫描，计算量相当大。
 * 为了加快检测的速度，在不同的应用场景可以根据实际的需求缩小检测范围，可以大大提高检测速度。
 * 比如在监控场景中，最大检测窗口不需要到0.7倍(0.7倍相当于整个镜头中被一个目标(如人脸)占满),可以根据镜头的距离减少最大检测窗口尺寸。
 * 再比如在手机自拍场景中，最小检测窗口也不需要到24x24，应该适当增大最小检测窗口的尺寸。
 * =====检测方向=====
 * 为了提高检测速度，在用检测窗口对图像进行扫描某个矩形区域的时候，如果这个矩形区域与已经检测到的目标矩形相交(之前不同尺寸的检测窗口检测到的)，
 * 那么就会跳过该矩形区域。
 * 那么在对检测范围内的所有检测窗口进行循环检测的时候，从最大窗口开始还是从最小窗口开始，检出的结果可能是不同的。
 * min_first 就是用于定义循环检测的方向
 * min_first 为true时 ，从最小检测窗口开始逐级放大检测窗口进行循环检测，会优先检出较小目标，
 * min_first 为false时，从最大检测窗口开始逐级缩小检测窗口进行循环检测，会优先检出较大目标。
 * min_first 默认值为false。
 */
typedef struct _detect_param{
	size_t detect_scale_level;		// 检测窗口缩放级别
	size_t detect_win_size;			// 检测窗口目标尺寸
	gf_float2 detect_range_f;		// 检测窗口范围(归一化尺寸) (s0为最大检测窗口,s1为最小检测窗口)
	gf_int2 detect_range_i;			// 检测窗口范围(整数尺寸)    (s0为最大检测窗口,s1为最小检测窗口)
	size_t detect_win_shrink_floor; // 为保证图像质量设定的检测窗口缩小尺寸下限
	bool min_first;					// 为true时从最小窗口逐级向上开始检测,false时相反
}detect_param;
/*
 * 生成缺省检测参数
 * */
inline detect_param make_default_detect_param(){
	detect_param param= { 0
		,DETECT_WIN_SIZE
		,{ DEFAULT_MAX_DETECT_WIN_RATIO,0.0f }
		,{ -1,-1 }
		,DEFAULT_DETECT_WIN_SHRINK_FLOOR
		,false
	};
	return param;
}
/*
 * 设置图像检测参数
 */
class GF_DLL_DECL detect_param_builder{
	detect_param param;
	void clean_i();
	void clean_f();
public:
	detect_param_builder():param(make_default_detect_param()){}
	detect_param_builder& set_detect_win_scale_level(size_t s = 0);
	/*
	 * 设置最大检测窗口尺寸(归一化)
	 * */
	detect_param_builder& set_max_size_ratio(float ratio);
	/*
	 * 设置最小检测窗口尺寸(归一化)
	 * */
	detect_param_builder& set_min_size_ratio(float ratio);
	/*
	 * 设置检测窗口范围尺寸(归一化)
	 * */
	detect_param_builder& set_detect_range(const gf_float2& range);
	/*
	 * 设置检测窗口范围尺寸
	 * */
	detect_param_builder& set_detect_range(const gf_int2& range);
	/*
	 * 设置最大检测窗口尺寸
	 * */
	detect_param_builder& set_max_size(int size);
	/*
	 * 设置最小检测窗口尺寸
	 * */
	detect_param_builder& set_min_size(int size);
	/*
	 * 设置是否从最小检测窗口开始逐步放大检测
	 * */
	detect_param_builder& set_min_first(bool min_first = true);
	detect_param_builder& set_detect_win_shrink_floor(size_t shrink_floor);
	/*
	 * 返回构造的检测参数对象
	 * */
	detect_param build();
};
/*
 * detect_cl 核心接口类
 */
struct GF_DLL_DECL detect_cl{
	/*
	 * 初始化,编译加载opencl kernel
	 * step			检测窗口逐级放大倍率(>1)
	 * 	最小检测窗口到最大检测窗口之间的每一级检测窗口之间的放大是一个固定放大比例，叫放大倍率，这个倍率在SDK初始化时就固定下来
	 * scale_size	检测窗口级数，
	 * 这决定着能检测到的目标最大尺寸，比如step为1.25，scale_size为30时 最大的检测窗口为pow(1.25,30-1)*24=15510
	 * 初始化函数只会被执行一次，第二次及以后的调用无效
	 */
	static void init(float step=DETECT_WIN_SCALE_RATIO,size_t scale_size=30);
	/*
	 * 根据detect_param参数对image_matrix指定的图像进行目标检测
	 * 目标检测是基于灰度图像处理的，
	 * 如果image_matrix不是灰度图像，在检测之前会将图像先转灰
	 * */
	static object_info_vector detect(const image_matrix& img, const detect_param& param=make_default_detect_param());
	/*
	 * 根据detect_param参数对image_matrix_v指定的图像进行目标检测
	 * */
	static object_info_vector detect(const image_matrix_v& img, const detect_param& param = make_default_detect_param()) {
		return detect(to_image_matrix(img), param);
	}
#if _MSC_VER>=1900 || __cplusplus>=201103L
	/*
	 * 右值引用版本,VS2015或支持c++11的编译器下有效
	 * 当image_matrix_v为灰度图像时，可以减少内存分配
	 * */
	static object_info_vector detect(image_matrix_v&& img, const detect_param& param =	make_default_detect_param());
#endif
	/*
	* 设置全局运行参数
	* debug_show  是否显示调试界面
	* kerne_message 是否显示kernel调试信息
	* 默认皆为false
	* */
	static void set_global_run_config(bool debug_show, bool kerne_message);
};

}/*namespace gdface*/
#endif /* FACEDETECT_DETECT_CL_H_ */
